package com.pmdesigns.utils;

import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import net.sf.persist.Persist;


/**
 * Source for database connections (wrapped in a Persist class)
 */
public class PersistMgr {
	private static DataSource ds;

	// increase the size of this cache for better performance
	private static PersistCache recycled = new PersistCache(3);

	// just for testing...need to initialize the db driver
	private static boolean initialized;

	// can't instantiate this class
	private PersistMgr() {
	}

	
	/**
	 * Get a Persist database connection object
	 */
    public static Persist getPersist() {
		Persist p = recycled.get();
		if (p != null) return p;
		
		try {
			// just for testing, use an in memory hsql db
			if (!initialized) {
				String driver = "org.hsqldb.jdbcDriver";
				try {
					Class.forName(driver);
					initialized = true;
				} catch (ClassNotFoundException e) {
					throw new RuntimeException("Driver not found: "+driver, e);
				}
			}
			
			Connection c = DriverManager.getConnection("jdbc:hsqldb:mem:testdb", "sa", "");
			return new Persist(c);
			
			/* real way...
			   
			  if (ds == null) {	

			  String dsName = "java:/comp/env/jdbc/testdb";
			  InitialContext cxt = new InitialContext();
			  if ( cxt == null ) {
			  throw new RuntimeException("Failed to get initial context!");
			  }

			  ds = (DataSource) cxt.lookup(dsName);
			  if ( ds == null ) {
			  throw new RuntimeException("Data source '"+dsName+"' not found!");
			  }
			  }
				
			  return new Persist(ds.getConnection());
				
		} catch (javax.naming.NamingException e) {
			throw new RuntimeException("Exception while getting initial context", e);
			*/

		} catch (java.sql.SQLException e) {
			throw new RuntimeException("Exception while getting data connection", e);
		}
    }

	
	/**
	 * Recycle a Persist database connection object.
	 * Calling this method after finishing with a Persist object is optional,
	 * but it will improve performance by reducing unnecessary creations/deletions.
	 */
	public static void recycle(Persist p) {
		recycled.put(p);
	}


	/**
	 * Very simple fixed size cache to hold recycled Persist objects
	 */
	static class PersistCache {
		Persist[] cache;
		int count;

		/**
		 * Create a cache with the indicated capacity
		 */
		PersistCache(int size) {
			count = 0;
			cache = new Persist[size];
		}

		/**
		 * Retrieve from cache or return null if cache is empty
		 */
		synchronized Persist get() {
			if (count > 0) {
				count--;
				Persist p = cache[count];
				cache[count] = null;
				return p;
			}
			return null;
		}

		/**
		 * Add to cache, if the cache isn't full
		 */
		synchronized void put(Persist p) {
			if (p != null && count < cache.length) {
				cache[count++] = p;
			}
		}
	}
}

